<template>
  <BasicModal
    v-bind="$attrs"
    @register="registerModal"
    defaultFullscreen
    :footer="null"
    :closable="false"
    :keyboard="false"
    class="jnpf-full-modal full-modal designer-modal dataSet-modal">
    <template #title>
      <div class="jnpf-full-modal-header">
        <div class="header-title">数据集名称：<a-input v-model:value="dataForm.fullName" placeholder="请输入" class="!w-200px"></a-input></div>
        <a-space class="options" :size="10">
          <a-button type="primary" @click="handleSubmit()" :disabled="btnLoading">{{ t('common.okText') }}</a-button>
          <a-button @click="closeModal()" :disabled="btnLoading">{{ t('common.cancelText') }}</a-button>
        </a-space>
      </div>
    </template>
    <div class="dataSet-modal-main">
      <div class="left-pane">
        <jnpf-select
          class="!w-full"
          v-model:value="dataForm.dbLinkId"
          showSearch
          :options="dbOptions"
          placeholder="选择数据库"
          @change="onDbLinkChange"
          :fieldNames="{ options: 'children' }" />
        <div class="left-pane-box">
          <InputSearch class="search-box" :placeholder="t('common.enterKeyword')" allowClear v-model:value="keyword" @search="handleSearchTable" />
          <BasicTree class="tree-box remove-active-tree" ref="leftTreeRef" v-bind="getTreeBindValue" />
        </div>
      </div>
      <div class="middle-pane">
        <a-tabs v-model:activeKey="dataForm.type" class="jnpf-content-wrapper-tabs">
          <a-tab-pane v-for="tab in tabList" :key="tab.id">
            <template #tab>{{ tab.fullName }}</template>
          </a-tab-pane>
          <template #rightExtra v-if="dataForm.type != 2">
            <a-dropdown>
              <a-button type="link">系统变量<DownOutlined /></a-button>
              <template #overlay>
                <a-menu>
                  <a-menu-item disabled>当前系统变量仅支持内部接口引用</a-menu-item>
                  <a-menu-divider />
                  <a-menu-item v-for="(item, index) in getSysVariableList" :key="index" @click="handleSysNodeClick(item.id)">
                    <span>{{ item.id }}</span>
                    <span style="float: right; color: #8492a6; padding-left: 10px">{{ item.fullName }}</span>
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </template>
        </a-tabs>
        <template v-if="dataForm.type != 2">
          <MonacoEditor class="h-full" ref="sqlEditorRef" language="sql" v-model="dataForm.dataConfigJson" />
        </template>
        <template v-else>
          <div class="config-tree-box">
            <div class="add-btn-box" v-if="!visualConfigJson.length">
              <a-button size="large" preIcon="icon-ym icon-ym-btn-add" @click="handleAdd()">新增数据库表</a-button>
            </div>
            <BasicTree
              class="tree-box remove-active-tree"
              ref="tableConfigTreeRef"
              :treeData="visualConfigJson"
              :fieldNames="fieldNames"
              defaultExpandAll
              v-else>
              <template #title="item">
                <div class="jnpf-tree__title" @click="handleEdit(item.table)">
                  <i class="mr-6px" :class="getIconClassName(item)" :title="getIconTitle(item)"></i>
                  {{ item.tableName }}
                  <span class="jnpf-tree__action">
                    <PlusOutlined class="ml-10px" title="添加" @click.stop="handleAdd(item.table)" v-if="getAddBtnShow(item.parentTable)" />
                    <DeleteOutlined class="ml-6px" title="删除" @click.stop="handleDelete(item.table)" />
                  </span>
                </div>
              </template>
            </BasicTree>
          </div>
          <div class="preview-box">
            <a-tabs v-model:activeKey="previewActiveKey" class="jnpf-content-wrapper-tabs">
              <a-tab-pane v-for="tab in previewTypeList" :key="tab.id" :tab="tab.fullName"></a-tab-pane>
              <template #rightExtra>
                <a-button type="link" preIcon="icon-ym icon-ym-filter" @click="openFilterConfig">筛选设置</a-button>
                <a-button type="link" preIcon="icon-ym icon-ym-Refresh" @click="handleGetPreviewData">刷新数据</a-button>
              </template>
            </a-tabs>
            <div class="preview-content" v-loading="previewLoading" v-show="previewActiveKey === 1">
              <div class="preview-tip">预览数据仅显示20条数据</div>
              <BasicTable
                :data-source="state.previewData"
                :columns="state.previewColumns"
                size="small"
                :pagination="false"
                :showTableSetting="false"
                v-if="!!state.previewColumns.length" />
            </div>
            <div class="preview-content" v-loading="previewLoading" v-show="previewActiveKey === 2">
              <a-textarea v-model:value="state.previewSqlText" readonly class="preview-content-sql" />
              <a-tooltip placement="bottom" :title="t('common.copyText')">
                <CopyOutlined class="copy-btn" @click="handleCopySql" v-if="state.previewSqlText" />
              </a-tooltip>
            </div>
          </div>
        </template>
      </div>
      <!-- <div class="right-pane">
        <FieldTable :list="parameterJson" @item-click="handleItemClick" />
      </div> -->
    </div>
    <TableConfigDrawer v-bind="getTableConfigBind" @register="registerTableConfigDrawer" @confirm="onTreeNodeConfirm" />
    <FilterConfigDrawer :sysVariableList="getSysVariableList" @register="registerFilterConfigDrawer" @confirm="onFilterConfigConfirm" />
  </BasicModal>
</template>
<script lang="ts" setup>
  import { getDataSourceSelector } from '@/api/systemData/dataSource';
  import { getDataModelListAll, getDataModelFieldList } from '@/api/systemData/dataModel';
  import { getFields, getPreviewData } from '@/api/system/dataSet';
  import { reactive, toRefs, ref, unref, computed } from 'vue';
  import { PlusOutlined, DeleteOutlined, DownOutlined, CopyOutlined } from '@ant-design/icons-vue';
  import { BasicModal, useModalInner } from '@/components/Modal';
  import { useDrawer } from '@/components/Drawer';
  import { useMessage } from '@/hooks/web/useMessage';
  import { useI18n } from '@/hooks/web/useI18n';
  import { cloneDeep } from 'lodash-es';
  import { BasicTree, TreeActionType } from '@/components/Tree';
  import { MonacoEditor } from '@/components/CodeEditor';
  import { InputSearch } from 'ant-design-vue';
  import FieldTable from '@/views/systemData/dataInterface/components/Field/Field.vue';
  import { buildUUID } from '@/utils/uuid';
  import TableConfigDrawer from './TableConfigDrawer.vue';
  import FilterConfigDrawer from './FilterConfigDrawer.vue';
  import { useCopyToClipboard } from '@/hooks/web/useCopyToClipboard';
  import { BasicTable } from '@/components/Table';

  interface State {
    dataForm: any;
    dataSetList: any[];
    parameterJson: any[];
    fieldJson: any[];
    dbOptions: any[];
    treeLoading: boolean;
    btnLoading: boolean;
    keyword: string;
    treeData: any[];
    isEdit: boolean;
    visualConfigJson: any[];
    filterConfigJson: any;
    previewActiveKey: number;
    currentNode: string;
    previewSqlText: string;
    previewData: any[];
    previewColumns: any[];
    previewLoading: boolean;
  }

  const props = defineProps({
    type: { type: String, default: '' },
  });
  const tabList = [
    { fullName: 'SQL语句', id: 1 },
    { fullName: '配置式', id: 2 },
  ];
  const previewTypeList = [
    { fullName: '数据预览', id: 1 },
    { fullName: 'SQL预览', id: 2 },
  ];
  const fieldNames = { key: 'table' };
  const defaultDataForm = {
    jnpfId: '',
    id: '',
    fullName: '',
    dbLinkId: '0',
    dataConfigJson: '',
    visualConfigJson: '',
    filterConfigJson: '',
    parameterJson: '',
    fieldJson: '',
    objectType: props.type === 'print' ? 'printVersion' : '',
    type: 1,
  };
  const defaultFilterConfigJson = {
    ruleList: [],
    matchLogic: 'and',
  };
  const state = reactive<State>({
    dataForm: {
      jnpfId: '',
      id: '',
      fullName: '',
      dbLinkId: '0',
      dataConfigJson: '',
      visualConfigJson: '',
      filterConfigJson: '',
      parameterJson: '',
      fieldJson: '',
      objectType: '',
      type: 1,
    },
    dataSetList: [],
    parameterJson: [],
    fieldJson: [],
    dbOptions: [],
    treeLoading: true,
    btnLoading: false,
    keyword: '',
    treeData: [],
    isEdit: false,
    visualConfigJson: [],
    filterConfigJson: {},
    previewActiveKey: 1,
    currentNode: '',
    previewSqlText: '',
    previewData: [],
    previewColumns: [],
    previewLoading: false,
  });
  const { dataForm, parameterJson, dbOptions, keyword, treeData, btnLoading, visualConfigJson, previewActiveKey, previewLoading } = toRefs(state);
  const { t } = useI18n();
  const { createMessage, createConfirm } = useMessage();
  const emit = defineEmits(['register', 'confirm']);
  const sqlEditorRef = ref(null);
  const leftTreeRef = ref(null);
  const tableConfigTreeRef = ref<Nullable<TreeActionType>>(null);
  const [registerModal, { closeModal, changeLoading }] = useModalInner(init);
  const [registerTableConfigDrawer, { openDrawer: openTableConfigDrawer }] = useDrawer();
  const [registerFilterConfigDrawer, { openDrawer: openFilterConfigDrawer }] = useDrawer();

  const getSysVariableList = computed(() => {
    const list = [
      { id: '@formId', fullName: '当前表单ID' },
      { id: '@currentUser', fullName: '当前用户' },
      { id: '@currentUsersAndSubordinates', fullName: '当前用户及下属' },
      { id: '@organization', fullName: '当前组织' },
      { id: '@currentOrganizationAndSuborganization', fullName: '当前组织及子组织' },
      { id: '@chargeorganization', fullName: '当前分管组织' },
    ];
    if (state.dataForm.type === 1) {
      const extraList = [
        { id: '@lotSnowID', fullName: '批量生成不同雪花ID' },
        { id: '@snowFlakeID', fullName: '系统生成雪花ID' },
      ];
      list.unshift(...extraList);
    }
    return list;
  });
  const getTreeBindValue = computed(() => {
    const key = +new Date();
    const data: any = {
      defaultExpandAll: false,
      treeData: state.treeData,
      loading: state.treeLoading,
      loadData: onLoadData,
      onSelect: handleTreeSelect,
      key,
    };
    return data;
  });
  const getTableConfigBind = computed(() => ({
    linkId: state.dataForm.dbLinkId,
    sysVariableList: unref(getSysVariableList),
    getTableConfigTree: getTableConfigTree,
  }));

  function init(data) {
    state.btnLoading = false;
    state.previewActiveKey = 1;
    handleClearPreviewData();
    state.keyword = '';
    state.isEdit = !!data.data;
    state.dataSetList = cloneDeep(data.list);
    const dataForm = data.data ? cloneDeep(data.data) : cloneDeep(defaultDataForm);
    state.dataForm = dataForm;
    if (!state.isEdit) state.dataForm.jnpfId = buildUUID();
    state.parameterJson = dataForm.parameterJson ? JSON.parse(dataForm.parameterJson) : [];
    state.fieldJson = dataForm.fieldJson ? JSON.parse(dataForm.fieldJson) : [];
    state.visualConfigJson = dataForm.visualConfigJson ? JSON.parse(dataForm.visualConfigJson) : [];
    state.filterConfigJson = dataForm.filterConfigJson ? JSON.parse(dataForm.filterConfigJson) : cloneDeep(defaultFilterConfigJson);
    changeLoading(true);
    getDataSourceSelector().then(res => {
      let list = res.data.list || [];
      list = list.filter(o => o.children && o.children.length);
      if (list[0]?.children?.length) list[0] = list[0].children[0];
      delete list[0].children;
      state.dbOptions = list;
      changeLoading(false);
      getTableList();
    });
  }
  function onDbLinkChange() {
    getTableList(true);
  }
  function getTableList(isClean = false) {
    state.treeLoading = true;
    const query = {
      linkId: state.dataForm.dbLinkId,
      keyword: state.keyword,
      pageSize: 1000000,
    };
    getDataModelListAll(query)
      .then(res => {
        state.treeLoading = false;
        state.treeData = res.data.list.map(o => ({
          ...o,
          fullName: o.tableName ? o.table + '(' + o.tableName + ')' : o.table,
          isLeaf: false,
          id: o.table,
          icon: o.type == 1 ? 'icon-ym icon-ym-view' : 'icon-ym icon-ym-generator-tableGrid',
        }));
        if (isClean) {
          state.dataForm.dataConfigJson = '';
          state.visualConfigJson = [];
          state.filterConfigJson = cloneDeep(defaultFilterConfigJson);
          handleClearPreviewData();
        }
      })
      .catch(() => {
        state.treeLoading = false;
        state.treeData = [];
      });
  }
  function onLoadData(node) {
    return new Promise((resolve: (value?: unknown) => void) => {
      getDataModelFieldList(state.dataForm.dbLinkId, node.dataRef.table).then(res => {
        const data = res.data.list.map(o => ({
          ...o,
          isLeaf: true,
          fullName: o.fieldName ? o.field + '(' + o.fieldName + ')' : o.field,
          id: node.dataRef.table + '-' + o.field,
        }));
        getTree().updateNodeByKey(node.eventKey, { children: data, isLeaf: !data.length });
        resolve();
      });
    });
  }
  function handleSearchTable() {
    getTableList();
    treeData.value = [];
    handleClearPreviewData();
  }
  function handleSysNodeClick(data) {
    (sqlEditorRef.value as any)?.insert(data);
  }
  function handleItemClick(item) {
    item.field && (sqlEditorRef.value as any)?.insert('{' + item.field + '}');
  }
  function handleTreeSelect(keys) {
    const selectedNode: any = getTree()?.getSelectedNode(keys[0]);
    const content = selectedNode.isLeaf ? selectedNode.field : selectedNode.table;
    (sqlEditorRef.value as any)?.insert(content);
  }
  function getTree() {
    const tree = unref(leftTreeRef);
    if (!tree) {
      throw new Error('tree is null!');
    }
    return tree as any;
  }
  // 更新字段
  function updateFieldList(data) {
    state.btnLoading = true;
    changeLoading(true);
    getFields(data)
      .then(res => {
        data.children = res.data.map(o => ({ ...o, jnpfId: data.fullName + '.' + o.id }));
        changeLoading(false);
        state.btnLoading = false;
        updateDataSetList(data);
      })
      .catch(() => {
        changeLoading(false);
        state.btnLoading = false;
      });
  }
  function getTableConfigTree() {
    const tree = unref(tableConfigTreeRef);
    if (!tree) {
      throw new Error('tree is null!');
    }
    return tree;
  }
  // 删除数据库表
  function handleDelete(table) {
    createConfirm({
      iconType: 'warning',
      title: t('common.tipTitle'),
      content: `确定删除数据库表?`,
      onOk: () => {
        getTableConfigTree().deleteNodeByKey(table);
        handleClearPreviewData();
      },
    });
  }
  function getAddBtnShow(parentTable) {
    if (!parentTable) return true;
    return state.visualConfigJson.some(o => o.table === parentTable);
  }
  function getIconClassName(item) {
    if (!item.parentTable) return 'icon-ym icon-ym-generator-tableGrid';
    if (item.relationConfig.type === 1) return 'icon-ym icon-ym-left-join';
    if (item.relationConfig.type === 2) return 'icon-ym icon-ym-right-join';
    if (item.relationConfig.type === 3) return 'icon-ym icon-ym-inner-join';
    if (item.relationConfig.type === 4) return 'icon-ym icon-ym-full-join';
    return 'icon-ym icon-ym-generator-tableGrid';
  }
  function getIconTitle(item) {
    if (!item.parentTable) return '';
    if (item.relationConfig.type === 1) return '左连接';
    if (item.relationConfig.type === 2) return '右连接';
    if (item.relationConfig.type === 3) return '内连接';
    if (item.relationConfig.type === 4) return '全连接';
    return '';
  }
  // 新增数据库表
  function handleAdd(table = '') {
    state.currentNode = table;
    if (state.currentNode) {
      const node: any = getTableConfigTree().getSelectedNode(state.currentNode);
      if (node?.children?.length >= 2) {
        createMessage.warning('最多只能添加两个子表');
        return;
      }
    }
    openTableConfigDrawer(true, { parentTable: table });
  }
  function handleEdit(table) {
    state.currentNode = table;
    const node: any = getTableConfigTree().getSelectedNode(state.currentNode);
    openTableConfigDrawer(true, { parentTable: node.parentTable, data: node });
  }
  function onTreeNodeConfirm(data, isEdit, isDelChild) {
    if (!isEdit) {
      if (!state.currentNode) return state.visualConfigJson.push(data);
      const node = getTableConfigTree().getSelectedNode(state.currentNode);
      node?.children?.push(data);
      handleClearPreviewData();
      return;
    }
    if (isDelChild) data.children = [];
    getTableConfigTree().updateNodeByKey(state.currentNode, data);
    handleClearPreviewData();
  }
  function openFilterConfig() {
    if (!state.visualConfigJson.length) return createMessage.error('请先配置数据库表');
    openFilterConfigDrawer(true, { data: state.filterConfigJson, visualConfigJson: state.visualConfigJson });
  }
  function onFilterConfigConfirm(data) {
    state.filterConfigJson = data;
    handleClearPreviewData();
  }
  // 获取预览数据
  function handleGetPreviewData() {
    if (!state.visualConfigJson.length) return createMessage.error('请先配置数据库表');
    state.previewLoading = true;
    const data = {
      ...state.dataForm,
      parameterJson: state.parameterJson.length ? JSON.stringify(state.parameterJson) : '',
      fieldJson: state.fieldJson.length ? JSON.stringify(state.fieldJson) : '',
      visualConfigJson: state.visualConfigJson.length ? JSON.stringify(state.visualConfigJson) : '',
      filterConfigJson: state.filterConfigJson ? JSON.stringify(state.filterConfigJson) : '',
    };
    getPreviewData(data)
      .then(res => {
        state.previewData = res.data.previewData;
        let previewColumns = res.data.previewColumns.map(o => ({ title: o.title, dataIndex: o.title, key: o.title }));
        state.previewColumns = [...previewColumns];
        state.previewSqlText = res.data.previewSqlText;
        state.previewLoading = false;
      })
      .catch(() => {
        handleClearPreviewData();
      });
  }
  // 清空预览数据
  function handleClearPreviewData() {
    state.previewLoading = false;
    state.previewData = [];
    state.previewColumns = [];
    state.previewSqlText = '';
  }
  function handleCopySql() {
    if (!state.previewSqlText) return;
    const { isSuccessRef } = useCopyToClipboard(state.previewSqlText);
    unref(isSuccessRef) && createMessage.success('复制成功');
  }
  // 更新数据集列表
  function updateDataSetList(data) {
    if (!state.isEdit) {
      state.dataSetList.push(data);
    } else {
      for (let i = 0; i < state.dataSetList.length; i++) {
        if (state.dataSetList[i].jnpfId === data.jnpfId) {
          state.dataSetList[i] = data;
          break;
        }
      }
    }
    emit('confirm', state.dataSetList);
    closeModal();
  }
  function handleSubmit() {
    if (!state.dataForm.fullName) {
      createMessage.error('请输入数据集名称');
      return;
    }
    const reg = /(^_([A-Za-z0-9]_?)*$)|(^[A-Za-z](_?[A-Za-z0-9])*_?$)/;
    if (!reg.test(state.dataForm.fullName)) {
      createMessage.error('数据集名称只能包含字母、数字、下划线，并且以字母开头');
      return;
    }
    let boo = false;
    for (let i = 0; i < state.dataSetList.length; i++) {
      if (state.dataForm.jnpfId !== state.dataSetList[i].jnpfId && state.dataForm.fullName === state.dataSetList[i].fullName) {
        boo = true;
        break;
      }
    }
    if (boo) {
      createMessage.error('数据集名称已存在');
      return;
    }
    if (state.dataForm.type === 1 && !state.dataForm.dataConfigJson) {
      createMessage.error('请输入SQL语句');
      return;
    }
    if (state.dataForm.type === 2 && !state.visualConfigJson.length) {
      createMessage.error('请配置数据库表');
      return;
    }
    const data = {
      ...state.dataForm,
      parameterJson: state.parameterJson.length ? JSON.stringify(state.parameterJson) : '',
      fieldJson: state.fieldJson.length ? JSON.stringify(state.fieldJson) : '',
      visualConfigJson: state.visualConfigJson.length ? JSON.stringify(state.visualConfigJson) : '',
      filterConfigJson: state.filterConfigJson ? JSON.stringify(state.filterConfigJson) : '',
    };
    updateFieldList(data);
  }
</script>
<style lang="less">
  .dataSet-modal {
    .dataSet-modal-main {
      height: 100%;
      overflow: hidden;
      display: flex;
      justify-content: space-between;
      overflow: hidden;
      .left-pane {
        flex-shrink: 0;
        width: 350px;
        margin-right: 10px;
        .left-pane-box {
          margin-top: 8px;
          border-radius: 4px;
          height: calc(100% - 40px);
          border: 1px solid @border-color-base;
          background-color: @component-background;
          overflow: hidden;
          .search-box {
            padding: 10px;
          }
          .tree-box {
            height: calc(100% - 52px);
            overflow: auto;
            overflow-x: hidden;
          }
        }
      }
      .middle-pane {
        background-color: @component-background;
        border: 1px solid @border-color-base;
        border-radius: 4px;
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        .title {
          border-top: 1px solid @border-color-base;
        }
        .title-box {
          height: 36px;
          line-height: 36px;
          display: flex;
          justify-content: space-between;
          color: @text-color-label;
          font-size: 14px;
          padding: 0 10px;
          flex-shrink: 0;
          border-bottom: 1px solid @border-color-base;
        }
        .tabs-box {
          overflow: unset;
          :deep(.ant-tabs-tab:first-child) {
            margin-left: 20px;
          }
        }
        .table-actions {
          flex-shrink: 0;
          border-top: 1px dashed @border-color-base;
          text-align: center;
        }
        .top-box {
          display: flex;
          .main-box {
            flex: 1;
            margin-right: 18px;
          }
        }
        .jnpf-content-wrapper-tabs {
          flex-shrink: 0;
          .ant-btn-link {
            padding-left: 0;
            padding-right: 0;
            margin-left: 20px;
          }
        }
        .config-tree-box {
          flex: 1;
          min-height: 200px;
          .jnpf-tree .ant-tree .ant-tree-node-content-wrapper,
          .jnpf-tree .ant-tree .ant-tree-switcher,
          .jnpf-tree__title {
            line-height: 50px;
            height: 50px;
          }
          .add-btn-box {
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
          }
        }
        .preview-box {
          flex-shrink: 0;
          border-top: 1px solid @border-color-base1;
          .preview-content {
            position: relative;
            height: 380px;
            .preview-tip {
              color: @text-color-label;
              text-align: right;
              line-height: 40px;
              padding: 0 10px;
            }
            .copy-btn {
              position: absolute;
              right: 15px;
              top: 15px;
              color: @text-color-label;
              cursor: pointer;
              font-size: 18px;
            }
            .preview-content-sql {
              height: 100%;
              border-radius: 0;
              border: unset !important;
              box-shadow: unset !important;
              padding: 10px 20px;
            }
          }
        }
      }
      .right-pane {
        width: 350px;
        flex-shrink: 0;
        display: flex;
        flex-direction: column;
        height: calc(100% + 9px);
        overflow: hidden;
        margin-left: 10px;
        .right-pane-btn {
          flex-shrink: 0;
        }
        .field-table-box {
          background-color: @component-background;
        }
      }
    }
  }
</style>
